﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TekaMUD.Engine.Commands;
using TekaMUD.Engine.Commands.Parser;

namespace TekaMUD.Engine.Blocks
{
	/// <summary>
	/// Adds description and context to a game entity. Visible objects in game.
	/// </summary>
	public abstract class GameObject : GameEntity
	{
		private string _examineDescription;

		public GameObjectArticle? Article { get; protected set; }

		/// <summary>
		/// Object's name
		/// </summary>
		public string Name { get; protected set; }

		/// <summary>
		/// Simple description of the object, in response to "look" command. This text
		/// is output as is to the player, without any prefixesd or sufixes.
		/// </summary>
		public virtual string LookDescription { get; set; }


		/// <summary>
		/// The plural name of the object. By default it's name + "s"
		/// </summary>
		public virtual string PluralizedNoun { get { return Name + "s"; } }

		/// <summary>
		/// Other names by which the object is also known as.
		/// </summary>
		public string[] Synonyms { get; protected set; }

		/// <summary>
		/// Current adjectives that describe the object.
		/// </summary>
		public List<string> Adjectives { get; protected set; }


		public GameObject()
		{
			Adjectives = new List<string>();
		}

		public bool MatchName(ArgumentNode noun)
		{
			if (noun.NounComponents.Length > 1)
				return MatchName(noun.NounComponents[1], noun.NounComponents[0]);
			else
				return MatchName(noun.NounComponents[0], null);
		}

		/// <summary>
		/// Detailled description of the object, for examination
		/// </summary>
		public virtual string ExamineDescription
		{
			get
			{
				if (_examineDescription == null)
					return LookDescription;
				else
					return _examineDescription;
			}
			set
			{
				_examineDescription = value;
			}
		}

		/// <summary>
		/// Tries to match a specified name against this object.
		/// </summary>
		public bool MatchName(string targetName, string adjective)
		{
			// Too specific match
			if (adjective != null && Adjectives == null)
				return false;

			/// Try a more specific match first.
			if (adjective != null && Adjectives != null)
			{
				foreach (string adj in Adjectives)
					if (adj.Equals(adjective, StringComparison.InvariantCultureIgnoreCase))
						goto checkName;

				return false;
			}

			checkName:

			if (targetName.Equals(Name, StringComparison.InvariantCultureIgnoreCase))
			{
				return true;
			}

			if (PluralizedNoun.Equals(targetName, StringComparison.InvariantCultureIgnoreCase))
			{
				return true;
			}

			if (Synonyms != null)
				foreach (string syn in Synonyms)
					if (syn.Equals(targetName, StringComparison.InvariantCultureIgnoreCase))
						return true;

			return false;
		}

		public override string ToString()
		{
			return UID.ToString("n") + " - " + AdjectivizedName;		
		}

		public void AddAdjective(string adj)
		{
			Adjectives.Add(adj);
		}


		/// <summary>
		/// Returns the name of the object including existing objects if any.
		/// </summary>
		public string AdjectivizedName
		{
			get
			{
				if (Adjectives == null || Adjectives.Count == 0)
					return Name;

				if (Adjectives.Count == 1)
					return Adjectives[0] + " " + Name;

				string an = "";

				foreach (string adj in Adjectives)
					an += adj + " ";

				return an + Name;
			}
		}
	}
}
